package com.csap.framework.oauth2.client.rest;

import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import com.csap.framework.cloud.request.RequestAttributes;
import com.csap.framework.cloud.request.RequestContext;
import com.csap.framework.extension.result.ResultParam;
import com.csap.framework.extension.result.ResultUtil;
import com.csap.framework.oauth2.UserInfo;
import com.csap.framework.oauth2.UserInfoEndpoint;
import com.csap.framework.oauth2.client.Oauth2ClientProperties;
import com.csap.framework.oauth2.open.RoleOpenApi;
import com.csap.framework.oauth2.request.LogoutRequest;
import com.csap.framework.oauth2.request.MobileLoginRequest;
import com.csap.framework.oauth2.request.PlatformRequest;
import com.csap.framework.oauth2.request.RegisterRequest;
import com.csap.framework.oauth2.request.RolesRequest;
import com.csap.framework.oauth2.request.RolesResponse;
import com.csap.framework.oauth2.request.TokenRequest;
import com.csap.framework.oauth2.request.UpdateRequest;
import com.csap.framework.oauth2.request.UserPermissionsVo;
import com.csap.framework.oauth2.request.UserRolesRequest;
import com.csap.framework.oauth2.response.RegisterResponse;
import com.csap.framework.oauth2.server.Oauth2ServerEndpointApi;
import com.csap.framework.oauth2.type.PlatformType;
import com.csap.framework.util.Assert;
import com.csap.framework.util.StringUtil;
import com.csap.mybatisplus.page.Page;
import lombok.AllArgsConstructor;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;

import static cn.dev33.satoken.LoginUtil.CLIENT_ID;
import static cn.dev33.satoken.LoginUtil.CLIENT_SECRET;
import static cn.dev33.satoken.LoginUtil.PLATFORM;
import static cn.dev33.satoken.LoginUtil.USER_TYPE;

/**
 * 授权客户端本地模式
 *
 * @Author ycf
 * @Date 2023/11/9 14:53
 */
@AllArgsConstructor
public class Oauth2ClientApiLocal implements Oauth2ClientApi {
    @Resource
    private Oauth2ServerEndpointApi serverEndpointApi;
    private UserInfoEndpoint userInfoEndpoint;
    /**
     * 客户端配置
     */
    @Resource
    private Oauth2ClientProperties clientProperties;
    /**
     * token配置
     */
    @Resource
    private SaTokenConfig saTokenConfig;
    @Resource
    private RoleOpenApi roleOpenApi;

    @Override
    public ResultParam<UserInfo> getUserinfo() {
        return s(userInfoEndpoint.userInfo());
    }

    private <T> T header(T t) {
        return header(t, null, null, null);
    }

    /**
     * 统一的头部处理
     *
     * @param platform  平台
     * @param loginType 登录类型
     * @param userType  用户类型
     */
    private <T> T header(T t, String platform, String loginType, String userType) {
        if (StringUtil.isEmpty(platform)) {
            platform = clientProperties.getPlatform();
        }
        RequestAttributes attributes = RequestContext.getRequestAttributes();
        if (StringUtil.isEmpty(loginType)) {
            loginType = clientProperties.getLoginType();
        }
        if (StringUtil.isEmpty(userType)) {
            userType = clientProperties.getUserType();
        }
        if (StringUtil.isNotEmpty(platform)) {
            attributes.addHeader(PLATFORM, platform);
        }
        Assert.notEmpty(loginType, "登录类型未配置");
        Assert.notEmpty(userType, "用户类型未配置");

        attributes.addHeader(saTokenConfig.getLoginType(), loginType);
        attributes.addHeader(CLIENT_ID, clientProperties.getClientId());
        attributes.addHeader(CLIENT_SECRET, clientProperties.getClientSecret());
        attributes.addHeader(USER_TYPE, userType);
        return t;
    }

    @Override
    public ResultParam<String> queryUserRoleNameByOpenId(UserRolesRequest userRolesRequest) {
        return roleOpenApi.queryUserRoleNameByOpenId(userRolesRequest
                .clientId(clientProperties.getClientId())
                .clientSecret(userRolesRequest.getClient_secret()));
    }

    @Override
    public ResultParam<AccessTokenModel> token(TokenRequest tokenRequest) {
        return (ResultParam<AccessTokenModel>) serverEndpointApi.token(header(tokenRequest
                .clientId(StringUtil.isEmpty(tokenRequest.getClient_id()) ? clientProperties.getClientId() : tokenRequest.getClient_id())
                .clientSecret(StringUtil.isEmpty(tokenRequest.getClient_secret()) ? clientProperties.getClientSecret() : tokenRequest.getClient_secret()), tokenRequest.getPlatform(), tokenRequest.getLoginType(), tokenRequest.getUserType()));
    }

    @Override
    public ResultParam<Boolean> removeByOpenId(String openId) {
        return s(serverEndpointApi.removeByOpenId(header(openId), clientProperties.getClientId()));
    }

    @Override
    public ResultParam<UserInfo> userInfoId(String loginId) {
        return s(userInfoEndpoint.userInfo(loginId));
    }

    @Override
    public ResultParam<RegisterResponse> register(RegisterRequest registerRequest) {
        return s(serverEndpointApi.register(header(registerRequest.setClientId(clientProperties.getClientId())
                .setClientSecret(clientProperties.getClientSecret())
                .setLoginType(clientProperties.getLoginType()), registerRequest.getPlatform(), registerRequest.getLoginType(), registerRequest.getUserType())));
    }

    private <T> ResultParam<T> s(T s) {
        return ResultUtil.success(s);
    }

    @Override
    public ResultParam<RegisterResponse> onekeyRegister(RegisterRequest registerRequest) {
        return s(serverEndpointApi.onekeyRegister(header(registerRequest.setClientId(clientProperties.getClientId())
                .setClientSecret(clientProperties.getClientSecret())
                .setLoginType(clientProperties.getLoginType()), registerRequest.getPlatform(), registerRequest.getLoginType(), registerRequest.getUserType())));
    }

    @Override
    public ResultParam<AccessTokenModel> loginRegister(RegisterRequest registerRequest) {
        return serverEndpointApi.loginRegister(header(registerRequest.setClientId(clientProperties.getClientId())
                .setClientSecret(clientProperties.getClientSecret()), registerRequest.getPlatform(), registerRequest.getLoginType(), registerRequest.getUserType()));
    }

    @Override
    public ResultParam<AccessTokenModel> loginRegisterMobile(RegisterRequest registerRequest) {
        return s(serverEndpointApi.loginRegisterMobile(header(registerRequest.setClientId(clientProperties.getClientId())
                .setClientSecret(clientProperties.getClientSecret())
                .setLoginType(clientProperties.getLoginType()), registerRequest.getPlatform(), registerRequest.getLoginType(), registerRequest.getUserType())));
    }

    @Override
    public ResultParam<AccessTokenModel> loginMobile(MobileLoginRequest mobileRequest) {
        return s(serverEndpointApi.loginMobile(header(mobileRequest.clientId(clientProperties.getClientId())
                .clientSecret(clientProperties.getClientSecret()), mobileRequest.getPlatform(), mobileRequest.getLoginType(), mobileRequest.getUserType())));
    }

    @Override
    public ResultParam<Boolean> updateByOpenId(UpdateRequest updateRequest) {
        return s(serverEndpointApi.updateByOpenId(header(updateRequest.clientId(clientProperties.getClientId())
                .clientSecret(clientProperties.getClientSecret())
                .loginType(clientProperties.getLoginType()), updateRequest.getPlatform(), updateRequest.getLoginType(), updateRequest.getUserType())));
    }

    @Override
    public ResultParam<Boolean> loginOut() {
        userInfoEndpoint.loginOut();
        return s(header(true));
    }

    @Override
    public ResultParam<Boolean> logoutByOpenId(LogoutRequest logoutRequest) {
        return s(userInfoEndpoint.logoutByOpenId(header(logoutRequest.clientId(clientProperties.getClientId()), logoutRequest.getPlatform(), logoutRequest.getLoginType(), logoutRequest.getUserType())));
    }

    @Override
    public ResultParam<Map<Long, RolesResponse>> findMapByIds(String ids) {
        return roleOpenApi.findMapByIds(ids);
    }

    @Override
    public ResultParam<Set<Long>> queryUserRolesByOpenId(UserRolesRequest userRolesRequest) {
        return roleOpenApi.queryUserRolesByOpenId(header(userRolesRequest.clientId(clientProperties.getClientId()).clientSecret(clientProperties.getClientSecret()), userRolesRequest.getPlatform(), userRolesRequest.getLoginType(), userRolesRequest.getUserType()));
    }

    @Override
    public ResultParam<Boolean> addUserRoles(UserRolesRequest userRolesRequest) {
        return roleOpenApi.addUserRoles(header(userRolesRequest.clientId(clientProperties.getClientId()).clientSecret(clientProperties.getClientSecret())));
    }

    @Override
    public ResultParam<Long> addRole(RolesRequest rolesModel) {
        return roleOpenApi.addRole(header(rolesModel.clientId(clientProperties.getClientId()).clientSecret(clientProperties.getClientSecret())));
    }

    @Override
    public ResultParam<Boolean> updateRole(RolesRequest rolesModel) {
        return roleOpenApi.updateRole(header(rolesModel.clientId(clientProperties.getClientId()).clientSecret(clientProperties.getClientSecret())));
    }

    @Override
    public ResultParam<Boolean> remove(Long id) {
        return roleOpenApi.remove(header(id));
    }

    @Override
    public ResultParam<Page<RolesResponse>> queryPage(RolesRequest rolesModel) {
        return roleOpenApi.queryPage(header(rolesModel.clientId(clientProperties.getClientId()).clientSecret(clientProperties.getClientSecret())));
    }

    @Override
    public ResultParam<Boolean> saveOrUpdateUserPermissions(UserPermissionsVo vo) {
        return roleOpenApi.saveOrUpdateUserPermissions(header(vo));
    }

    @Override
    public ResultParam<Boolean> addPlatform(PlatformRequest platformRequest) {
        return ResultUtil.success(serverEndpointApi.addPlatform(platformRequest));
    }

    @Override
    public ResultParam<Boolean> updatePlatform(PlatformRequest platformRequest) {
        return ResultUtil.success(serverEndpointApi.updatePlatform(platformRequest));
    }
}
